// ThreadPool.hpp
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include "Log.hpp"

class ThreadPool
{
private:
    ThreadPool(int num)
        : _num(num), _stop(true)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool &) {}

public:
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
    static ThreadPool *GetInstance(int num)
    {
        if (single_instance == nullptr)
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            pthread_mutex_lock(&lock);
            if (single_instance == nullptr)
            {
                single_instance = new ThreadPool(num);
                if (!single_instance->InitThreadPool())
                {
                    delete single_instance;
                    pthread_mutex_unlock(&lock);
                    return nullptr;
                }
            }
            pthread_mutex_unlock(&lock);
        }
        return single_instance;
    }
    bool InitThreadPool()
    {
        _stop = false;
        for (int i = 0; i < _num; ++i)
        {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0)
            {
                LOG(FATAL, "create thread pool error!");
                return false;
            }
        }
        LOG(INFO, "create thread pool success.");
        return true;
    }
    static void *ThreadRoutine(void *args)
    {
        ThreadPool *tp = static_cast<ThreadPool *>(args);
        while (!tp->_stop)
        {
            Task task;
            tp->Lock();
            while (tp->TaskQueueIsempty())
            {
                tp->ThreadWait(); // 被唤醒的时候，一定是占有互斥锁的
            }

            tp->PopTask(task);
            tp->Unlock();

            task.ProcessOn();
        }
    }
    void PushTask(Task task) // in
    {
        Lock();
        _task_queue.push(task);
        ThreadWakeup();
        Unlock();
    }
    void PopTask(Task &task) // out
    {
        task = _task_queue.front();
        _task_queue.pop();
    }
    bool IsStop()
    {
        return _stop;
    }

private:
    bool TaskQueueIsempty()
    {
        return _task_queue.empty();
    }
    void Lock()
    {
        pthread_mutex_lock(&_lock);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&_lock);
    }
    void ThreadWait()
    {
        pthread_cond_wait(&_cond, &_lock);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

private:
    int _num;   // 线程池里线程的个数
    bool _stop; // 线程池是否是运行状态
    std::queue<Task> _task_queue;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;

    static ThreadPool *single_instance;
};

ThreadPool *ThreadPool::single_instance = nullptr;